目標:30–45 分鐘把 ESP32-CAM 跑起來,畫面穩、不卡、還能「一鍵拍照」。
風格:像朋友在旁邊指路+給你一堆現成範例。
本篇可直接貼到部落格(純 Markdown),圖表用 ASCII 呈現,平台相容。
USB-TTL | ESP32-CAM | 小提醒 |
---|---|---|
5V | 5V | 優先穩定供電(5V/≥1A) |
GND | GND | 共地,線不要太細 |
TX | U0R | 交叉連線 |
RX | U0T | 交叉連線 |
IO0 | GND | 只在「刷機」時接上 |
刷完後:拔掉 IO0→GND,按 RST,回一般模式。
esp32 by Espressif Systems
Huge APP
或 Default
File → Examples → ESP32 → Camera → CameraWebServer
http://192.168.1.123
)常見端點(不同版本可能略差):
Path | 功能 |
---|---|
/ |
瀏覽器控制台(切解析度、開關閃光燈等) |
/stream |
MJPEG 串流 |
/capture |
拍一張 JPG(按一下就存圖) |
一個人的「小直播台」
(你) ──打開瀏覽器──> http://<ESP32-IP>/
└─點「Start Stream」→ 影像即時出現
解析度 延遲(越少越順)
QVGA (320x240) ■■■□□□□ ≈120ms
VGA (640x480) ■■■■□□ ≈200ms
SVGA (800x600) ■■■■■□ ≈320ms
XGA (1024x768) ■■■■■■ ≈480ms
建議:先用 QVGA / VGA 把網路與畫面調穩,再往上拉。
/shot
直接回傳 JPEG)#include <WiFi.h>
#include <WebServer.h>
#include "esp_camera.h"
WebServer srv(80);
void handleShot(){
camera_fb_t * fb = esp_camera_fb_get();
if(!fb){ srv.send(500,"text/plain","fail"); return; }
srv.sendHeader("Content-Type","image/jpeg");
srv.send_P(200,"image/jpeg",(const char*)fb->buf, fb->len);
esp_camera_fb_return(fb);
}
void setup(){
// 初始化 Wi-Fi + camera_config_t(略)
srv.on("/shot", handleShot);
srv.begin();
}
void loop(){ srv.handleClient(); }
好用情境
IFTTT/Webhook/排程 → GET http://<ESP32-IP>/shot → 得到一張新照片!
#include "esp_camera.h"
#include "FS.h"
#include "SD_MMC.h"
void setup(){
// ... init camera_config_t ...
SD_MMC.begin("/sdcard", true); // 1-bit 模式較穩
}
void loop(){
camera_fb_t *fb = esp_camera_fb_get();
if(!fb) return;
String path = "/" + String(millis()) + ".jpg";
File f = SD_MMC.open(path, FILE_WRITE);
if(f){ f.write(fb->buf, fb->len); f.close(); }
esp_camera_fb_return(fb);
delay(5 * 60 * 1000); // 5 分鐘
}
產生縮時影片(在電腦或 Pi 上)
ffmpeg -framerate 12 -pattern_type glob -i "*.jpg" -vf "scale=1280:-1" timelapse.mp4
#include "esp_camera.h"
#define BUTTON 12 // 依實際接線
#define LED_PIN 4 // 一些板子把閃光燈接在 GPIO 4
void setup(){
// init camera...
pinMode(BUTTON, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
}
void loop(){
if(digitalRead(BUTTON)==LOW){
digitalWrite(LED_PIN, HIGH); delay(60); // 補光一下
camera_fb_t *fb = esp_camera_fb_get();
// TODO: 存到 SD 或送到你的 /upload API
esp_camera_fb_return(fb);
digitalWrite(LED_PIN, LOW);
delay(800); // 簡單防彈跳
}
}
客製玩法
/upload
,做雲端相簿。sensor_t * s = esp_camera_sensor_get();
調畫質:sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_VGA); // QVGA/VGA/SVGA/XGA...
s->set_brightness(s, 1); // -2..2
s->set_contrast(s, 1); // -2..2
s->set_saturation(s, 0); // -2..2
[無法上傳草稿?] → (IO0 沒接 GND?) → 接上 → 成功
└─(TX/RX 反了?) → 交叉接法: TX→U0R, RX→U0T
[Camera init failed?] → (供電不足?) → 換 5V/≥1A & 短線
└─(PSRAM 沒開?) → Arduino 設定啟用 PSRAM
[看不到IP?] → (Wi-Fi 密碼/SSID 錯?) → 重寫 → 序列埠複製 IP
└─(訊號弱?) → 靠近 AP / 改用 20MHz / 有線 AP
[串流很卡?] → 降解析度→關多餘後處理→靠近 AP→再逐步拉高
Python 在 PC/Pi 端觀測 FPS(也能當 demo)
import cv2, time
cap = cv2.VideoCapture("http://<ESP32-IP>/stream")
t, n = time.time(), 0
while True:
ok, frame = cap.read()
if not ok: break
n += 1
if time.time() - t >= 2:
print("FPS ≈", n/2)
n, t = 0, time.time()
cv2.imshow("ESP32-CAM", frame)
if cv2.waitKey(1)==27: break
簡易「帶寬估算」(概念)
解析度 平均JPEG大小 10fps 帶寬估
QVGA ~25KB ~2.0 Mbps
VGA ~45KB ~3.6 Mbps
SVGA ~70KB ~5.6 Mbps
(實際依畫面複雜度/壓縮而變動)
/capture
成功拿到一張 JPG